home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '93 / Hacks '93 / HackTV & Example panel comp. / HackTV.c < prev    next >
Text File  |  1993-08-18  |  29KB  |  1,168 lines

  1. /*
  2.     File:        HackTV.c
  3.  
  4.     Contains:    Hack TV routines.
  5.             
  6.                 Refer to develop Issue 14, "Video Digitizing Under QuickTime",
  7.                 for details on this code.
  8.                 
  9.                 This code requires QuickTime 1.5.
  10.                 
  11.                 This version of HackTV.c includes a section to link in the
  12.                 example video panel component.
  13.  
  14.     Written by:    Gary Woodcock
  15.  
  16.     Copyright:    © 1992-1993 by Apple Computer, Inc.
  17.  
  18.     Change History (most recent first):
  19.  
  20. */
  21.  
  22. //-----------------------------------------------------------------------
  23. // Includes
  24.  
  25. #include <Menus.h>
  26. #include <Windows.h>
  27. #include <QuickDraw.h>
  28. #include <OSEvents.h>
  29. #include <Resources.h>
  30. #include <Desk.h>
  31. #include <Fonts.h>
  32. #include <ToolUtils.h>
  33. #include <QuickTimeComponents.h>
  34. #include <Scrap.h>
  35. #include <Printing.h>
  36. #include <Errors.h>
  37. #include <SysEqu.h>
  38. #include <Folders.h>
  39. #include <Script.h>
  40. #include <Memory.h>
  41. #include <GestaltEqu.h>
  42.  
  43. #ifndef THINK_C
  44.     #include <Packages.h>
  45. #endif THINK_C
  46.  
  47. #include "softVdig.h"
  48. #include "ExampleVideoPanelPrivate.h"
  49.  
  50. //-----------------------------------------------------------------------
  51. // Constants
  52.  
  53. // Menu bar
  54. enum
  55. {
  56.     kMenuBarID = 128
  57. };
  58.  
  59. // Menus
  60. enum
  61. {
  62.     kAppleID = 128,
  63.     kFileID,
  64.     kEditID,
  65.     kMonitorID
  66. };
  67.  
  68. // Apple menu items
  69. enum
  70. {
  71.     kAboutItem = 1
  72. };
  73.  
  74. // File menu items
  75. enum
  76. {
  77.     kPageSetupItem = 1,
  78.     kPrintItem,
  79.     kQuitItem = 4
  80. };
  81.  
  82. // Edit menu items
  83. enum
  84. {
  85.     kUndoItem = 1,
  86.     kCutItem = 3,
  87.     kCopyItem,
  88.     kPasteItem,
  89.     kClearItem
  90. };
  91.  
  92. // Monitor menu items
  93. enum
  94. {
  95.     kVideoSettingsItem = 1,
  96.     kSoundSettingsItem,
  97.     kQuarterSizeItem = 4,
  98.     kHalfSizeItem,
  99.     kFullSizeItem,
  100.     kRecordItem = 8
  101. };
  102.  
  103. // Dialog IDs
  104. enum
  105. {
  106.     kAboutDLOGID = 128,
  107.     kMonitorDLOGID
  108. };
  109.  
  110. // Common DITL items
  111. enum
  112. {
  113.     kAboutOKButton = 1,
  114.     kAboutOKButtonOutline
  115. };
  116.  
  117. //-----------------------------------------------------------------------
  118. // Globals
  119.  
  120. MenuHandle                gAppleMenu;
  121. MenuHandle                gFileMenu;
  122. MenuHandle                gEditMenu;
  123. MenuHandle                gMonitorMenu;
  124. EventRecord                gTheEvent;
  125. Boolean                    gQuitFlag;
  126. SeqGrabComponent        gSeqGrabber;
  127. SGChannel                gVideoChannel;
  128. SGChannel                gSoundChannel;
  129. WindowPtr                gMonitor;
  130. Rect                    gActiveVideoRect;
  131. PicHandle                gMonitorPICT;
  132. Boolean                    gFullSize;
  133. Boolean                    gHalfSize;
  134. Boolean                    gQuarterSize;
  135. THPrint                    gPrintRec;
  136. AlignmentProcRecordPtr    gSeqGrabberAlignProc;
  137. VideoDigitizerComponent    gVdig;
  138.  
  139. //-----------------------------------------------------------------------
  140. // Prototypes
  141.  
  142. static void
  143. DoInit (void);
  144.  
  145. static void
  146. DoMenuSetup (void);
  147.  
  148. static void
  149. HandleEvent (void);
  150.  
  151. static void
  152. HandleMouseDown    (void);
  153.  
  154. static void
  155. AdjustMenus (void);
  156.  
  157. static void
  158. Enable (Handle menu, short item, Boolean ok);
  159.  
  160. static void
  161. HandleMenu (long menu);
  162.  
  163. static void
  164. DoAboutDialog (void);
  165.  
  166. static void
  167. DoQuit (void);
  168.  
  169. pascal void
  170. AboutDrawProc (DialogPtr theDialog, short theItemNum);
  171.  
  172. static OSErr
  173. XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn);
  174.  
  175. pascal Boolean
  176. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  177.     short *itemHit, long refCon);
  178.  
  179. static Boolean
  180. HasQuickTime15 (void);
  181.  
  182. //-----------------------------------------------------------------------
  183.  
  184. main (void)
  185. {
  186.     // Init
  187.     DoInit();
  188.     DoMenuSetup();
  189.     
  190.     // Eat events until done
  191.     do
  192.     {
  193.         HandleEvent();
  194.     }
  195.     while (!gQuitFlag);
  196.     
  197.     // Take off, eh?
  198.     ExitToShell();
  199. }
  200.  
  201. //-----------------------------------------------------------------------
  202.  
  203. static void
  204. DoInit (void)
  205. {
  206.     ComponentDescription    theDesc;
  207.     ComponentResult            result = noErr;
  208.     Component                sgCompID = 0L;
  209.     GrafPtr                    savedPort;
  210.     Component                vdigCompID;            // kck
  211.     Component                xmplPanelID;
  212.     
  213.     // Set up quit flag
  214.     gQuitFlag = false;
  215.     
  216.     // MacMantra™
  217.     MaxApplZone();
  218.     InitGraf (&qd.thePort);
  219.     InitFonts();
  220.     FlushEvents (everyEvent, 0);
  221.     InitWindows();
  222.     InitMenus();
  223.     TEInit();
  224.     InitDialogs (0L);
  225.     InitCursor();
  226.     EnterMovies();
  227.     MoreMasters();
  228.     MoreMasters();
  229.     MoreMasters();
  230.     MoreMasters();
  231.     
  232.     // Init stuff
  233.     gSeqGrabber = 0L;
  234.     gVideoChannel = 0L;
  235.     gSoundChannel = 0L;
  236.     gMonitorPICT = nil;
  237.     gPrintRec = (THPrint) NewHandleClear (sizeof (TPrint));
  238.     
  239.     // Find and open a sequence grabber
  240.     theDesc.componentType = SeqGrabComponentType;
  241.     theDesc.componentSubType = 0L;
  242.     theDesc.componentManufacturer = 'appl';
  243.     theDesc.componentFlags = 0L;
  244.     theDesc.componentFlagsMask = 0L;    
  245.     sgCompID = FindNextComponent (nil, &theDesc);
  246.     if (sgCompID != 0L)
  247.     {
  248.         gSeqGrabber = OpenComponent (sgCompID);
  249.     }
  250.     
  251.     // Find the softVdig
  252.     #ifdef DEBUG_IT
  253.         vdigCompID = RegisterSoftVdig();
  254.     #else
  255.         theDesc.componentType = videoDigitizerComponentType;
  256.         theDesc.componentSubType = 'soft';
  257.         theDesc.componentManufacturer = 'jph ';
  258.         theDesc.componentFlags = 0L;
  259.         theDesc.componentFlagsMask = 0L;
  260.         vdigCompID = FindNextComponent (nil, &theDesc);
  261.         SetDefaultComponent (vdigCompID, defaultComponentAnyFlagsAnyManufacturerAnySubType);
  262.     #endif DEBUG_IT
  263.     
  264.     theDesc.componentType = videoDigitizerComponentType;
  265.     theDesc.componentSubType = 0L;
  266.     theDesc.componentManufacturer = 0L;
  267.     theDesc.componentFlags = 0L;
  268.     theDesc.componentFlagsMask = 0L;
  269.     vdigCompID = FindNextComponent (nil, &theDesc);
  270.  
  271.     // Register the example video panel component
  272.     #ifdef DEBUG_ME
  273.         xmplPanelID = RegisterExampleVideoPanel();
  274.     #endif DEBUG_ME
  275.  
  276.     // If we got a sequence grabber, set it up
  277.     if (gSeqGrabber != 0L)
  278.     {
  279.         // Get the monitor
  280.         gMonitor = GetNewDialog (kMonitorDLOGID, nil, (WindowPtr) -1L);
  281.         if (gMonitor != nil)
  282.         {
  283.             // Initialize the sequence grabber
  284.             GetPort (&savedPort);
  285.             SetPort (gMonitor);
  286.             ShowWindow (gMonitor);        
  287.             result = SGInitialize (gSeqGrabber);
  288.             if (result == noErr)
  289.             {
  290.                 result = SGSetGWorld (gSeqGrabber, (CGrafPtr) gMonitor, nil);
  291.                 
  292.                 // Get a video channel
  293.                 result = SGNewChannel (gSeqGrabber, VideoMediaType, &gVideoChannel);
  294.                 if ((gVideoChannel != nil) && (result == noErr))
  295.                 {
  296.                     short    width;
  297.                     short    height;
  298.                     
  299.                     gQuarterSize = false;
  300.                     gHalfSize = true;
  301.                     gFullSize = false;
  302.                     
  303.                     result = SGGetSrcVideoBounds (gVideoChannel, &gActiveVideoRect);
  304.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 2;
  305.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 2;
  306.                     SizeWindow (gMonitor, width, height, false);
  307.                     
  308.                     result = SGSetChannelUsage (gVideoChannel, seqGrabPreview | seqGrabRecord | seqGrabPlayDuringRecord);
  309.                     result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  310.                 }
  311.                 
  312.                 // Get a sound channel
  313.                 result = SGNewChannel (gSeqGrabber, SoundMediaType, &gSoundChannel);
  314.                 if ((gSoundChannel != nil) && (result == noErr))
  315.                 {
  316.                     if (HasQuickTime15())
  317.                     {
  318.                         // There is a bug in QuickTime 1.5 where a SGChannel of type sound
  319.                         // will return successfully if there is no sound driver present.
  320.                         // To get around this, if we're running QT 1.5, we call 
  321.                         // SGGetSoundInputDriver after a successful SGNewChannel call for
  322.                         // a sound channel to find out if we really got one.  QuickTime
  323.                         // 1.6 has fixed this problem.
  324.                         
  325.                         short    sndDrvrRefNum = SGGetSoundInputDriver (gSoundChannel);
  326.                         
  327.                         if (sndDrvrRefNum == 0)
  328.                         {
  329.                             result = SGDisposeChannel (gSeqGrabber, gSoundChannel);
  330.                             gSoundChannel = nil;
  331.                         }
  332.                     }
  333.                     
  334.                     if (gSoundChannel != nil)
  335.                     {
  336.                         result = SGSetChannelUsage (gSoundChannel, seqGrabPreview | seqGrabRecord);
  337.                         
  338.                         // Set the volume low to prevent feedback when we start the preview,
  339.                         // in case the mic is anywhere near the speaker.
  340.                         result = SGSetChannelVolume (gSoundChannel, 0x0010);
  341.                     }
  342.                 }
  343.                 
  344.                 // Get the alignment proc (for use when dragging the monitor)
  345.                 result = SGGetAlignmentProc (gSeqGrabber, gSeqGrabberAlignProc);
  346.                 
  347.                 // Get ready…
  348.                 SGPrepare (gSeqGrabber, true, true);
  349.             }
  350.             
  351.             // Go!
  352.             if(result == noErr) result = SGStartPreview (gSeqGrabber);
  353.             SetPort (savedPort);
  354.         }
  355.     }
  356. }
  357.  
  358. //-----------------------------------------------------------------------
  359.  
  360. static void
  361. DoMenuSetup (void)
  362. {    
  363.     Handle    theMenuBar = GetNewMBar (kMenuBarID);
  364.     
  365.     // Set up our menus
  366.     SetMenuBar (theMenuBar);
  367.     gAppleMenu = GetMHandle (kAppleID);
  368.     gFileMenu = GetMHandle (kFileID);
  369.     gEditMenu = GetMHandle (kEditID);
  370.     gMonitorMenu = GetMHandle (kMonitorID);
  371.     AddResMenu (gAppleMenu, 'DRVR');
  372.     
  373.     // Last minute adjustments…
  374.     AdjustMenus();
  375. }
  376.  
  377. //-----------------------------------------------------------------------
  378.  
  379. static void
  380. HandleEvent (void)
  381. {
  382.     ComponentResult    result = noErr;
  383.  
  384.     // Do system stuff
  385.     HiliteMenu (0);
  386.     SystemTask();
  387.     
  388.     // Give some time to the sequence grabber
  389.     if (gSeqGrabber != 0L)
  390.         result = SGIdle (gSeqGrabber);
  391.     
  392.     // Suck an event
  393.     if (WaitNextEvent (everyEvent, &gTheEvent, 0, 0))
  394.     {
  395.         // What was it?
  396.         switch (gTheEvent.what)
  397.         {
  398.             case mouseDown:
  399.             {
  400.                 // Handle it
  401.                 HandleMouseDown();
  402.                 break;
  403.             }
  404.             case keyDown:
  405.             case autoKey:
  406.             {
  407.                 char    theChar = gTheEvent.message & charCodeMask;
  408.                 long    theMenu = MenuKey (theChar);
  409.  
  410.                 // Handle menu command keys
  411.                 HandleMenu (theMenu);                
  412.                 break;
  413.             }
  414.             case updateEvt:
  415.             {
  416.                 if ((gMonitor != nil) && ((WindowPtr) (gTheEvent.message) == (WindowPtr) gMonitor))
  417.                 {
  418.                     // Eat the update
  419.                     BeginUpdate (gMonitor);
  420.                     EndUpdate (gMonitor);
  421.                 }
  422.                 break;
  423.             }
  424.             default:    // We don't really care about any other events, but you might, so feel free
  425.             {
  426.                 break;
  427.             }
  428.         }
  429.     }
  430. }
  431.  
  432. //-----------------------------------------------------------------------
  433.  
  434. static void
  435. HandleMouseDown (void)
  436. {    
  437.     WindowPtr    theWindow;
  438.     short        windowCode = FindWindow (gTheEvent.where, &theWindow);
  439.     
  440.     // Where was the mouse down?
  441.     switch (windowCode)
  442.     {
  443.         case inSysWindow:
  444.         { 
  445.             SystemClick (&gTheEvent, theWindow);
  446.             break;
  447.         }
  448.         case inMenuBar:
  449.         {
  450.             AdjustMenus();
  451.             HandleMenu (0L);
  452.             break;
  453.         }
  454.         case inDrag:
  455.         {
  456.             // Was it the monitor?
  457.             if (theWindow == gMonitor)
  458.             {
  459.                 ComponentResult    result = noErr;
  460.                 Rect            limitRect;
  461.                 RgnHandle        grayRgn = GetGrayRgn();
  462.                 Rect            boundsRect;
  463.                 
  464.                 // Find bounds
  465.                 if (grayRgn != nil)
  466.                 {
  467.                     limitRect = (*grayRgn)->rgnBBox;
  468.                 }
  469.                 else
  470.                 {
  471.                     limitRect = qd.screenBits.bounds;
  472.                 }
  473.                 
  474.                 // Pause the sequence grabber
  475.                 result = SGPause (gSeqGrabber, true);
  476.                 
  477.                 if (gVideoChannel != nil)
  478.                 {
  479.                     // Drag it with the totally cool DragAlignedWindow
  480.                       // Note that the sequence grabber can get real confused when you use this
  481.                       // call if you've got multiple video channels - this'll get fixed in the 
  482.                       // next release.  
  483.                       result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  484.                     DragAlignedWindow (theWindow, gTheEvent.where, &limitRect, &boundsRect, gSeqGrabberAlignProc);
  485.                 }
  486.                 else
  487.                 {
  488.                     DragWindow (theWindow, gTheEvent.where, &limitRect);
  489.                 }
  490.                 
  491.                 // Start up the sequence grabber
  492.                 result = SGPause (gSeqGrabber, false);
  493.             }
  494.             break;
  495.         }
  496.         default:
  497.         {
  498.             break;
  499.         }
  500.     }
  501. }
  502.  
  503. //-----------------------------------------------------------------------
  504.  
  505. static void
  506. AdjustMenus (void)
  507. {
  508.     register WindowPeek        wp = nil;
  509.     short                    kind = 0;
  510.     Boolean                    DA = false;
  511.     ComponentResult            result = noErr;
  512.     
  513.     // What kind of window is frontmost?
  514.     wp = (WindowPeek) FrontWindow();
  515.     kind = wp ? wp->windowKind : 0;
  516.     DA = kind < 0;
  517.     
  518.     // Set our menu item states appropriately
  519.     
  520.     // Apple menu
  521.     Enable ((Handle) gAppleMenu, kAboutItem, true);    
  522.     
  523.     // File menu
  524.     Enable ((Handle) gFileMenu, kPageSetupItem, true);
  525.     Enable ((Handle) gFileMenu, kPrintItem, (gVideoChannel != 0L ? true : false));
  526.     Enable ((Handle) gFileMenu, kQuitItem, true);
  527.  
  528.     // Edit menu
  529.     Enable ((Handle) gEditMenu, kUndoItem, DA);
  530.     Enable ((Handle) gEditMenu, kCutItem, DA || (gVideoChannel != 0L));
  531.     Enable ((Handle) gEditMenu, kCopyItem, DA || (gVideoChannel != 0L));
  532.     Enable ((Handle) gEditMenu, kPasteItem, DA);
  533.     Enable ((Handle) gEditMenu, kClearItem, DA);
  534.     
  535.     // Monitor menu
  536.     Enable ((Handle) gMonitorMenu, kVideoSettingsItem, (gVideoChannel != 0L ? true : false));
  537.     Enable ((Handle) gMonitorMenu, kSoundSettingsItem, (gSoundChannel != 0L ? true : false));
  538.     Enable ((Handle) gMonitorMenu, kQuarterSizeItem, (gVideoChannel != 0L ? true : false));
  539.     CheckItem (gMonitorMenu, kQuarterSizeItem, gQuarterSize);
  540.     Enable ((Handle) gMonitorMenu, kHalfSizeItem, (gVideoChannel != 0L ? true : false));
  541.     CheckItem (gMonitorMenu, kHalfSizeItem, gHalfSize);
  542.     Enable ((Handle) gMonitorMenu, kFullSizeItem, (gVideoChannel != 0L ? true : false));
  543.     CheckItem (gMonitorMenu, kFullSizeItem, gFullSize);
  544.     Enable ((Handle) gMonitorMenu, kRecordItem, (gVideoChannel != 0L ? true : false));
  545.     
  546.     // Draw it
  547.     DrawMenuBar();
  548. }
  549.  
  550. //-----------------------------------------------------------------------
  551.  
  552. static void
  553. Enable (Handle menu, short item, Boolean ok)
  554. {
  555.     // Utility routine to enable and disable menu items
  556.     if (ok)
  557.     {
  558.         EnableItem ((MenuHandle) menu, item);
  559.     }
  560.     else
  561.     {
  562.         DisableItem ((MenuHandle) menu, item);
  563.     }
  564. }
  565.  
  566. //-----------------------------------------------------------------------
  567.  
  568. static void
  569. HandleMenu (long theMenu)
  570. {    
  571.     long            mSelect;
  572.     short            menuID;
  573.     short            menuItem;
  574.     ComponentResult    result = noErr;    
  575.     Str255            menuItemStr;
  576.     
  577.     // Did we get a menu?
  578.     if (theMenu == 0L)
  579.     {
  580.         // Nope, get it from menu select
  581.         mSelect = MenuSelect (gTheEvent.where);
  582.     }
  583.     else
  584.     {
  585.         // Yep, use it
  586.         mSelect = theMenu;
  587.     }
  588.     
  589.     // Decode it
  590.     menuID = HiWord (mSelect);
  591.     menuItem = LoWord (mSelect);
  592.     
  593.     // Which menu is it?
  594.     switch (menuID)
  595.     {
  596.         case kAppleID:
  597.         {
  598.             if (menuItem == kAboutItem)
  599.             {
  600.                 // Do the boring about box
  601.                 DoAboutDialog();
  602.             }
  603.             else    // It's a DA
  604.             {
  605.                 Str255    name;
  606.                 GrafPtr    savedPort;
  607.                 
  608.                 // Open the DA
  609.                 GetPort (&savedPort);
  610.                 GetItem (gAppleMenu, menuItem, name);
  611.                 OpenDeskAcc (name);
  612.                 SetPort (savedPort);
  613.             }
  614.             break;
  615.         }
  616.         case kFileID:
  617.         {
  618.             switch (menuItem)
  619.             {
  620.                 case kPageSetupItem:
  621.                 {
  622.                     // Do the page setup dialog
  623.                     PrOpen();
  624.                     PrStlDialog (gPrintRec);
  625.                     PrClose();
  626.                     break;
  627.                 }
  628.                 case kPrintItem:
  629.                 {
  630.                     TPPrPort    printPort;
  631.                     TPrStatus    printStatus;
  632.                     
  633.                     // Copy a frame from the monitor
  634.                     if (gMonitorPICT != nil)
  635.                     {
  636.                         KillPicture (gMonitorPICT);
  637.                     }
  638.                     gMonitorPICT = nil;
  639.                     result = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  640.                     if ((result == noErr) && (gMonitorPICT != nil))
  641.                     {
  642.                         // Print it
  643.                         HLock ((Handle) gMonitorPICT);
  644.                         PrOpen();
  645.                         if (PrJobDialog (gPrintRec))
  646.                         {
  647.                             printPort = PrOpenDoc (gPrintRec, nil, nil);
  648.                             result = PrError();
  649.                             PrOpenPage (printPort, 0);
  650.                             result = PrError();
  651.                             DrawPicture (gMonitorPICT, &((**gMonitorPICT).picFrame));
  652.                             PrClosePage (printPort);
  653.                             result = PrError();
  654.                             PrCloseDoc (printPort);
  655.                             result = PrError();
  656.                             if ((**gPrintRec).prJob.bJDocLoop == bSpoolLoop)
  657.                             {
  658.                                 PrPicFile (gPrintRec, 0, 0, 0, &printStatus);
  659.                                 result = PrError();
  660.                             }
  661.                         }
  662.                         PrClose();
  663.                         result = PrError();
  664.                         HUnlock ((Handle) gMonitorPICT);
  665.                     }
  666.                     break;
  667.                 }
  668.                 case kQuitItem:
  669.                 {
  670.                     // Let's scram
  671.                     DoQuit();
  672.                     break;
  673.                 }
  674.             }
  675.             break;
  676.         }
  677.         case kEditID:
  678.         {
  679.             // Is this a DA kind of thing?
  680.             if (!SystemEdit (menuItem - 1))
  681.             {
  682.                 // We only do cut and copy
  683.                 if ((menuItem == kCutItem) || (menuItem == kCopyItem))
  684.                 {
  685.                     // Copy a frame from the monitor
  686.                     if (gMonitorPICT != nil)
  687.                     {
  688.                         KillPicture (gMonitorPICT);
  689.                     }
  690.                     gMonitorPICT = nil;
  691.                     result = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  692.                     if ((result == noErr) && (gMonitorPICT != nil))
  693.                     {
  694.                         result = ZeroScrap();
  695.                         HLock ((Handle) gMonitorPICT);
  696.                         result = PutScrap (GetHandleSize ((Handle) gMonitorPICT), 'PICT', *(Handle)gMonitorPICT);
  697.                         HUnlock ((Handle) gMonitorPICT);
  698.                         if (result != noErr)
  699.                         {
  700.                             // Cut or copy failed, probably due to lack of memory
  701.                         }
  702.                     }
  703.                 }
  704.             }
  705.             break;
  706.         }
  707.         case kMonitorID:
  708.         {
  709.             switch (menuItem)
  710.             {
  711.                 short        width;
  712.                 short        height;
  713.                 Rect        curBounds;
  714.                 Rect        curVideoRect;
  715.                 Rect        newVideoRect;
  716.                 Rect        newBounds;
  717.                 Rect        maxBoundsRect;
  718.                 GrafPtr        savedPort;
  719.                 RgnHandle    deadRgn;
  720.                 Rect        boundsRect;
  721.                     
  722.                 case kVideoSettingsItem:
  723.                 {
  724.                     if ((gSeqGrabber != 0L) && (gVideoChannel != 0L))
  725.                     {
  726.                         Rect    newActiveVideoRect;
  727.                         Rect    adjustedActiveVideoRect;
  728.                         
  729.                         // Get our current state
  730.                         result = SGGetChannelBounds (gVideoChannel, &curBounds);
  731.                         result = SGGetVideoRect (gVideoChannel, &curVideoRect);
  732.                         
  733.                         // Pause
  734.                         result = SGPause (gSeqGrabber, true);
  735.                         
  736.                         // Do the dialog thang
  737.                         result = SGSettingsDialog (gSeqGrabber, gVideoChannel, 0, 
  738.                             nil, 0L, SeqGrabberModalFilterProc, (long) StripAddress ((Ptr) gMonitor));
  739.                             
  740.                         // What happened?
  741.                         result = SGGetVideoRect (gVideoChannel, &newVideoRect);
  742.                         result = SGGetSrcVideoBounds (gVideoChannel, &newActiveVideoRect);
  743.  
  744.                         // Set up our port
  745.                         GetPort (&savedPort);
  746.                         SetPort (gMonitor);
  747.                         
  748.                         // Has our active rect changed?
  749.                         // If so, it's because our video standard changed (e.g., NTSC to PAL),
  750.                         // and we need to adjust our monitor window
  751.                         if (!EqualRect (&gActiveVideoRect, &newActiveVideoRect))
  752.                         {
  753.                             if (gFullSize)
  754.                             {
  755.                                 width = newActiveVideoRect.right - newActiveVideoRect.left;
  756.                                 height = newActiveVideoRect.bottom - newActiveVideoRect.top;
  757.                                 
  758.                                 gActiveVideoRect = newActiveVideoRect;
  759.                                 SizeWindow (gMonitor, width, height, false);
  760.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  761.                             }
  762.                             else if (gHalfSize)
  763.                             {
  764.                                 width = (newActiveVideoRect.right - newActiveVideoRect.left) / 2;
  765.                                 height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 2;
  766.                                 
  767.                                 gActiveVideoRect = newActiveVideoRect;
  768.                                 SizeWindow (gMonitor, width, height, false);
  769.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  770.                             }
  771.                             else if (gQuarterSize)
  772.                             {
  773.                                 width = (newActiveVideoRect.right - newActiveVideoRect.left) / 4;
  774.                                 height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 4;
  775.                                 
  776.                                 gActiveVideoRect = newActiveVideoRect;
  777.                                 SizeWindow (gMonitor, width, height, false);
  778.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  779.                             }
  780.                         }
  781.                         
  782.                         // Has our crop changed?
  783.                         // This code shows how to be crop video panel friendly
  784.                         // Two important things - 
  785.                         // 1) Be aware that you might have been cropped and adjust your
  786.                         //    video window appropriately
  787.                         // 2) Be aware that you might have been adjusted and attempt to
  788.                         //    account for this.  Adjusting refers to using the digitizer
  789.                         //    rect to "adjust" the active source rect within the maximum
  790.                         //    source rect.  This is useful if you're getting those nasty
  791.                         //    black bands on the sides of your video display - you can use
  792.                         //    the control-arrow key sequence to shift the active source 
  793.                         //    rect around when you're in the crop video panel
  794.                         
  795.                         adjustedActiveVideoRect = gActiveVideoRect;
  796.                         if (!EqualRect (&curVideoRect, &newVideoRect))
  797.                         {
  798.                             if ((newVideoRect.left < gActiveVideoRect.left) ||
  799.                                 (newVideoRect.right > gActiveVideoRect.right) ||
  800.                                 (newVideoRect.top < gActiveVideoRect.top) ||
  801.                                 (newVideoRect.bottom > gActiveVideoRect.bottom))
  802.                             {
  803.                                 if (newVideoRect.left < gActiveVideoRect.left)
  804.                                 {
  805.                                     adjustedActiveVideoRect.left = newVideoRect.left;
  806.                                     adjustedActiveVideoRect.right -= (gActiveVideoRect.left - newVideoRect.left);
  807.                                 }
  808.                                 if (newVideoRect.right > gActiveVideoRect.right)
  809.                                 {
  810.                                     adjustedActiveVideoRect.right = newVideoRect.right;
  811.                                     adjustedActiveVideoRect.left += (newVideoRect.right - gActiveVideoRect.right);
  812.                                 }
  813.                                 if (newVideoRect.top < gActiveVideoRect.top)
  814.                                 {
  815.                                     adjustedActiveVideoRect.top = newVideoRect.top;
  816.                                     adjustedActiveVideoRect.bottom -= (gActiveVideoRect.top - newVideoRect.top);
  817.                                 }
  818.                                 if (newVideoRect.bottom > gActiveVideoRect.bottom)
  819.                                 {
  820.                                     adjustedActiveVideoRect.bottom = newVideoRect.bottom;
  821.                                     adjustedActiveVideoRect.top += (newVideoRect.bottom - gActiveVideoRect.bottom);
  822.                                 }
  823.                                 newBounds = newVideoRect;
  824.                                 MapRect (&newBounds, &adjustedActiveVideoRect, &(gMonitor->portRect));
  825.                             }
  826.                             else    // Can't tell if we've been adjusted (digitizer rect is smaller on all sides
  827.                                     // than the active source rect)
  828.                             {
  829.                                 newBounds = newVideoRect;
  830.                                 MapRect (&newBounds, &gActiveVideoRect, &(gMonitor->portRect));
  831.                             }
  832.                             width = newBounds.right - newBounds.left;
  833.                             height = newBounds.bottom - newBounds.top;
  834.                             result = SGSetChannelBounds (gVideoChannel, &newBounds);
  835.                         }
  836.  
  837.                         // Clean out the part of the port that isn't being drawn in
  838.                         deadRgn = NewRgn();
  839.                         if (deadRgn != nil)
  840.                         {
  841.                             result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  842.                             result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  843.                             EraseRgn (deadRgn);
  844.                             DisposeRgn (deadRgn);
  845.                         }
  846.  
  847.                         SetPort (savedPort);
  848.                         
  849.                         // The pause that refreshes
  850.                         result = SGPause (gSeqGrabber, false);
  851.                     }
  852.                     break;
  853.                 }
  854.                 case kSoundSettingsItem:
  855.                 {
  856.                     if ((gSeqGrabber != 0L) && (gSoundChannel != 0L))
  857.                     {
  858.                         // Do the dialog thang
  859.                         result = SGSettingsDialog (gSeqGrabber, gSoundChannel, 0,
  860.                             nil, 0L, SeqGrabberModalFilterProc, (long) StripAddress ((Ptr) gMonitor));
  861.                     }
  862.                     break;
  863.                 }
  864.                 case kQuarterSizeItem:
  865.                 {
  866.                     // New width and height
  867.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 4;
  868.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 4;
  869.                     
  870.                     // Set flags and menus
  871.                     gQuarterSize = true;
  872.                     gHalfSize = false;
  873.                     gFullSize = false;
  874.                     AdjustMenus();
  875.                     
  876.                     // Resize the monitor
  877.                     GetPort (&savedPort);
  878.                     SetPort (gMonitor);
  879.                     result = SGPause (gSeqGrabber, true);
  880.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  881.                     maxBoundsRect = gMonitor->portRect;
  882.                     SizeWindow (gMonitor, width, height, false);
  883.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  884.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  885.  
  886.                     // Clean out part of port we're not drawing in
  887.                     deadRgn = NewRgn();
  888.                     if (deadRgn != nil)
  889.                     {
  890.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  891.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  892.                         EraseRgn (deadRgn);
  893.                         DisposeRgn (deadRgn);
  894.                     }
  895.                         
  896.                     SetPort (savedPort);
  897.                     result = SGPause (gSeqGrabber, false);
  898.                     break;
  899.                 }
  900.                 case kHalfSizeItem:
  901.                 {
  902.                     // New width and height
  903.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 2;
  904.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 2;
  905.                     
  906.                     // Set flags and menus
  907.                     gQuarterSize = false;
  908.                     gHalfSize = true;
  909.                     gFullSize = false;
  910.                     AdjustMenus();
  911.                     
  912.                     // Resize the monitor
  913.                     GetPort (&savedPort);
  914.                     SetPort (gMonitor);
  915.                     result = SGPause (gSeqGrabber, true);
  916.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  917.                     maxBoundsRect = gMonitor->portRect;
  918.                     SizeWindow (gMonitor, width, height, false);
  919.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  920.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  921.  
  922.                     // Clean out part of port we're not drawing in
  923.                     deadRgn = NewRgn();
  924.                     if (deadRgn != nil)
  925.                     {
  926.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  927.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  928.                         EraseRgn (deadRgn);
  929.                         DisposeRgn (deadRgn);
  930.                     }
  931.                         
  932.                     SetPort (savedPort);
  933.                     result = SGPause (gSeqGrabber, false);
  934.                     break;
  935.                 }
  936.                 case kFullSizeItem:
  937.                 {
  938.                     // New width and height
  939.                     width = gActiveVideoRect.right - gActiveVideoRect.left;
  940.                     height = gActiveVideoRect.bottom - gActiveVideoRect.top;
  941.                     
  942.                     // Set flags and menus
  943.                     gQuarterSize = false;
  944.                     gHalfSize = false;
  945.                     gFullSize = true;
  946.                     AdjustMenus();
  947.                     
  948.                     // Resize the monitor
  949.                     GetPort (&savedPort);
  950.                     SetPort (gMonitor);
  951.                     result = SGPause (gSeqGrabber, true);
  952.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  953.                     maxBoundsRect = gMonitor->portRect;
  954.                     SizeWindow (gMonitor, width, height, false);
  955.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  956.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  957.  
  958.                     // Clean out part of port we're not drawing in
  959.                     deadRgn = NewRgn();
  960.                     if (deadRgn != nil)
  961.                     {
  962.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  963.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  964.                         EraseRgn (deadRgn);
  965.                         DisposeRgn (deadRgn);
  966.                     }
  967.                         
  968.                     SetPort (savedPort);
  969.                     result = SGPause (gSeqGrabber, false);
  970.                     break;
  971.                 }
  972.                 case kRecordItem:
  973.                 {
  974.                     FSSpec    theFSSpec;
  975.                     long    savedDirID = *(long *) CurDirStore;
  976.                     long    dirID;
  977.                     short    savedVRefNum = *(short *) SFSaveDisk;
  978.                     short    vRefNum;
  979.                     
  980.                     result = FindFolder (kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  981.                         &vRefNum, &dirID);
  982.                     *(short *)SFSaveDisk = -vRefNum;
  983.                     *(long *)CurDirStore = dirID;
  984.                     
  985.                     result = FSMakeFSSpec (vRefNum, dirID, "\pHack MooV", &theFSSpec);
  986.                     result = DeleteMovieFile (&theFSSpec);
  987.                     result = CreateMovieFile (&theFSSpec, 'TVOD', smSystemScript,
  988.                         createMovieFileDontOpenFile | createMovieFileDontCreateMovie,
  989.                         nil, nil);
  990.                     result = SGStop (gSeqGrabber);
  991.                     result = SGSetDataOutput (gSeqGrabber, &theFSSpec, seqGrabToDisk);
  992.                     result = SGStartRecord (gSeqGrabber);
  993.                     while (!Button() && (result == noErr))
  994.                     {
  995.                         result = SGIdle (gSeqGrabber);
  996.                     }
  997.                     result = SGStop (gSeqGrabber);
  998.                     result = SGStartPreview (gSeqGrabber);
  999.                     
  1000.                     *(short *)SFSaveDisk = savedVRefNum;
  1001.                     *(long *)CurDirStore = savedDirID;
  1002.                     break;
  1003.                 }
  1004.                 default:
  1005.                 {
  1006.                     break;
  1007.                 }
  1008.             }
  1009.         }
  1010.         default:
  1011.         {
  1012.             break;
  1013.         }
  1014.     }
  1015. }
  1016.  
  1017. //-----------------------------------------------------------------------
  1018.  
  1019. static void
  1020. DoAboutDialog (void)
  1021. {
  1022.     short        itemHit;
  1023.     short        itemType;
  1024.     Handle        itemHandle;
  1025.     Rect        itemRect;
  1026.     DialogPtr    aboutDialog = GetNewDialog (kAboutDLOGID, nil, (WindowPtr)-1L);
  1027.  
  1028.     // Do the boring about dialog
  1029.     GetDItem (aboutDialog, kAboutOKButtonOutline, &itemType, &itemHandle, &itemRect);
  1030.     SetDItem (aboutDialog, kAboutOKButtonOutline, itemType, 
  1031.         (Handle) AboutDrawProc, &itemRect);
  1032.  
  1033.     ShowWindow (aboutDialog);
  1034.     do
  1035.     {
  1036.         ModalDialog (nil, &itemHit);
  1037.     }
  1038.     while (itemHit != kAboutOKButton);
  1039.     DisposDialog (aboutDialog);
  1040. }
  1041.  
  1042. //-----------------------------------------------------------------------
  1043.  
  1044. pascal void
  1045. AboutDrawProc (DialogPtr theDialog, short theItemNum)
  1046. {
  1047.     PenState    thePenState;
  1048.     OSErr        result = noErr;
  1049.     Rect        itemRect;
  1050.     Handle        itemHandle;
  1051.     short        itemType;
  1052.     
  1053.     // Set up the pen
  1054.     GetPenState (&thePenState);
  1055.     
  1056.     GetDItem (theDialog, theItemNum, &itemType, &itemHandle, &itemRect);
  1057.     
  1058.     // What item do we need to draw?
  1059.     switch (theItemNum)
  1060.     {
  1061.         case kAboutOKButtonOutline:
  1062.             PenNormal();
  1063.             PenMode (patCopy);
  1064.             PenSize (3, 3);
  1065.             InsetRect (&itemRect, -4, -4);
  1066.             FrameRoundRect (&itemRect, 16, 16);
  1067.             break;
  1068.         default:
  1069.             break;
  1070.     }
  1071.     
  1072.     // Restore the pen
  1073.     SetPenState (&thePenState);
  1074. }
  1075.  
  1076. //-----------------------------------------------------------------------
  1077.  
  1078. static OSErr
  1079. XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn)
  1080. {
  1081.     RgnHandle    srcRgnA = NewRgn();
  1082.     RgnHandle    srcRgnB = NewRgn();
  1083.     OSErr        result = noErr;
  1084.     
  1085.     if ((destRgn != nil) && (*destRgn != nil))
  1086.     {
  1087.         if ((srcRgnA != nil) &&
  1088.             (srcRgnB != nil))
  1089.         {
  1090.             RectRgn (srcRgnA, srcRectA);
  1091.             RectRgn (srcRgnB, srcRectB);
  1092.             XorRgn (srcRgnA, srcRgnB, *destRgn);
  1093.             DisposeRgn (srcRgnA);
  1094.             DisposeRgn (srcRgnB);
  1095.         }
  1096.         else
  1097.         {
  1098.             result = memFullErr;
  1099.         }
  1100.     }
  1101.     else
  1102.     {
  1103.         result = nilHandleErr;
  1104.     }
  1105.     return (result);
  1106. }
  1107.  
  1108. //-----------------------------------------------------------------------
  1109.  
  1110. pascal Boolean
  1111. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  1112.     short *itemHit, long refCon)
  1113. {
  1114.     // Ordinarily, if we had multiple windows we cared about, we'd handle
  1115.     // updating them in here, but since we don't, we'll just clear out
  1116.     // any update events meant for us
  1117.     
  1118.     Boolean    handled = false;
  1119.     
  1120.     if ((theEvent->what == updateEvt) && 
  1121.         ((WindowPtr) theEvent->message == (WindowPtr) refCon))
  1122.     {
  1123.         BeginUpdate ((WindowPtr) refCon);
  1124.         EndUpdate ((WindowPtr) refCon);
  1125.         handled = true;
  1126.     }
  1127.     return (handled);
  1128. }
  1129.  
  1130. //-----------------------------------------------------------------------
  1131.  
  1132. static Boolean
  1133. HasQuickTime15 (void)
  1134. {
  1135.     long    result;
  1136.     OSErr    err = Gestalt (gestaltQuickTime, &result);
  1137.     
  1138.     return (((err == noErr) & (result >= 0x0150)) ? true: false);
  1139. }
  1140.  
  1141. //-----------------------------------------------------------------------
  1142.  
  1143. static void
  1144. DoQuit (void)
  1145. {
  1146.     ComponentResult    result = noErr;
  1147.     
  1148.     // Clean up
  1149.     if (gSeqGrabber != 0L)
  1150.     {
  1151.         result = CloseComponent (gSeqGrabber);
  1152.         gSeqGrabber = 0L;
  1153.     }    
  1154.     
  1155.     if (gMonitor != nil)
  1156.     {
  1157.         DisposeWindow (gMonitor);
  1158.     }
  1159.     
  1160.     // Set quit flag
  1161.     gQuitFlag = true;
  1162.     
  1163.     ExitMovies();
  1164. }
  1165.  
  1166. //-----------------------------------------------------------------------
  1167.  
  1168.